package com.yang.usb;

import androidx.appcompat.app.AppCompatActivity;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.yang.usb.receiver.OpenAccessoryReceiver;
import com.yang.usbserial.util.HexDump;
import com.yang.usbserial.util.LogUtils;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class UsbaccessoryaoaActivity extends AppCompatActivity implements OpenAccessoryReceiver.OpenAccessoryListener, View.OnClickListener {

    private TextView usbaccessorylog;
    private EditText usbaccessorymessage;

    private Button usbaccessorysend;

    private static final int SEND_MESSAGE_SUCCESS = 0;
    private static final int RECEIVER_MESSAGE_SUCCESS = 1;
    private static final String USB_ACTION = "com.tlkj.usb.accessory";

    private UsbManager mUsbManager;
    private OpenAccessoryReceiver mOpenAccessoryReceiver;
    private ParcelFileDescriptor mParcelFileDescriptor;
    private FileInputStream mFileInputStream;
    private FileOutputStream mFileOutputStream;
    private ExecutorService mThreadPool;
    private byte[] mBytes = new byte[1025];
    private Handler mHandler;
    private int currentFileIndex = 0; // 当前文件的索引

    private boolean receivingFile = false;
    private int currentFileSize = 0;
    private byte[] currentFileData; // 用于接收文件数据
    private int currentFileDataOffset = 0;

    private int fileDataSize = 0;
    private String[] parts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_usbaccessoryaoa);
        usbaccessorylog = findViewById(R.id.usbaccessorylog);
        usbaccessorysend = findViewById(R.id.usbaccessorysend);
        usbaccessorymessage = findViewById(R.id.usbaccessorymessage);
        initUsbCommunication();
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case SEND_MESSAGE_SUCCESS:
                        // Handle send message success
                        break;
                    case RECEIVER_MESSAGE_SUCCESS:
                        usbaccessorylog.setText(msg.obj + "%");
                        break;
                }
            }
        };
    }

    private void initUsbCommunication() {
        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        mOpenAccessoryReceiver = new OpenAccessoryReceiver(this);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(USB_ACTION), 0);
        IntentFilter intentFilter = new IntentFilter(USB_ACTION);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        registerReceiver(mOpenAccessoryReceiver, intentFilter);

        UsbAccessory[] accessories = mUsbManager.getAccessoryList();
        UsbAccessory usbAccessory = (accessories == null ? null : accessories[0]);
        if (usbAccessory != null) {
            if (mUsbManager.hasPermission(usbAccessory)) {
                openAccessory(usbAccessory);
            } else {
                mUsbManager.requestPermission(usbAccessory, pendingIntent);
            }
        }
    }

    private void openAccessory(UsbAccessory usbAccessory) {
        mParcelFileDescriptor = mUsbManager.openAccessory(usbAccessory);
        if (mParcelFileDescriptor != null) {
            configureAccessoryStreams();
            mThreadPool = Executors.newFixedThreadPool(3);
            mThreadPool.execute(() -> {
                try {
                    int bytesRead = 0;
                    while (true) {
                        bytesRead = mFileInputStream.read(mBytes);
                        if (bytesRead > 0) {
                            // Handle received data
                            processReceivedData(bytesRead);
                        }
                    }
                } catch (IOException e) {
                    handleException(e);
                }
            });
        }
    }

    private void configureAccessoryStreams() {
        FileDescriptor fileDescriptor = mParcelFileDescriptor.getFileDescriptor();
        mFileInputStream = new FileInputStream(fileDescriptor);
        mFileOutputStream = new FileOutputStream(fileDescriptor);
    }

    private boolean discardCurrentData = false;

    private void processReceivedData(int bytesRead) {
        LogUtils.e("接受的长度：" + bytesRead);
        if (receivingFile) {
            if (currentFileData == null) {
                currentFileData = new byte[currentFileSize];
            }
            if (discardCurrentData) {
                // 当验证失败时，丢弃当前数据
                LogUtils.e("验证失败，丢弃数据");
                discardCurrentData = false; // 重置标志
            } else {
                if ((bytesRead - 1) > currentFileSize) {//表示接受的大于文件长度不对
                    LogUtils.e("表示接受的文件长度大于现在当前文件总长度");
                    return;
                }
                // 将数据块添加到当前文件数据中
                int copyLength = Math.min(bytesRead, currentFileData.length - currentFileDataOffset);
                System.arraycopy(mBytes, 0, currentFileData, currentFileDataOffset, copyLength);
                currentFileDataOffset += copyLength;


                if (currentFileDataOffset >= currentFileSize) {//表示文件接受最后
                    // 数据块接收完毕，但不足1KB，此时验证LRC
                    byte receivedLRC = mBytes[bytesRead - 1];
                    byte[] dataWithoutLRC = new byte[bytesRead - 1];
                    System.arraycopy(mBytes, 0, dataWithoutLRC, 0, bytesRead - 1);
                    byte expectedLRC = calculateLRC(dataWithoutLRC);
                    if (receivedLRC == expectedLRC) {
                        // 数据块验证通过
                        // 文件保存逻辑
                        saveReceivedFileData(dataWithoutLRC, dataWithoutLRC.length, currentFileIndex);
                        sendDataToHost(HexDump.str2HexStr("OK"));
                    } else {
                        // 数据块验证失败，应答 ERR 并等待重发
                        sendDataToHost(HexDump.str2HexStr("ERR"));
                    }

                    // 清空当前数据块
                    currentFileData = null;
                    currentFileDataOffset = 0;

                    currentFileIndex++;
                    if (currentFileIndex < parts.length - 1) {
                        currentFileSize = HexDump.hexStringToAlgorism(parts[currentFileIndex + 1]);
                        LogUtils.e("下一个文件大小" + currentFileSize);
                        fileDataSize = 0;
                        Message msg1 = new Message();
                        msg1.what = RECEIVER_MESSAGE_SUCCESS;
                        msg1.obj = 0;
                        mHandler.sendMessage(msg1);
                        currentFileData = new byte[currentFileSize];
                    } else {
                        Message msg1 = new Message();
                        msg1.what = RECEIVER_MESSAGE_SUCCESS;
                        msg1.obj = 100;
                        mHandler.sendMessage(msg1);
                        // 所有文件都已接收完毕
                        currentFileData = null;
                        currentFileSize = 0;
                        receivingFile = false;
                        LogUtils.e("所有文件都已接收完毕");
                        sendDataToHost("END");
                    }

                }

                // 每次接收到数据块就进行LRC验证
                if (currentFileDataOffset >= 1025) {
                    if (bytesRead < 1024) {
                        // 数据块接收完毕，但不足1KB，此时验证LRC
                        byte receivedLRC = mBytes[bytesRead - 1];
                        byte[] dataWithoutLRC = new byte[bytesRead - 1];
                        System.arraycopy(mBytes, 0, dataWithoutLRC, 0, bytesRead - 1);
                        byte expectedLRC = calculateLRC(dataWithoutLRC);
                        if (receivedLRC == expectedLRC) {
                            // 数据块验证通过
                            // 文件保存逻辑
                            fileDataSize = fileDataSize + (bytesRead - 1);
                            Message msg = new Message();
                            msg.what = RECEIVER_MESSAGE_SUCCESS;
                            msg.obj = (fileDataSize / currentFileData.length) * 100;
                            mHandler.sendMessage(msg);
                            LogUtils.e("保存文件" + currentFileData.length);
                            saveReceivedFileData(currentFileData, bytesRead - 1, currentFileIndex);
//                            sendDataToHost("OK");
                        } else {
                            // 数据块验证失败，应答 ERR 并等待重发
                            sendDataToHost(HexDump.str2HexStr("ERR"));
                        }

                        // 清空当前数据块
                        currentFileData = null;
                        currentFileDataOffset = 0;

                        currentFileIndex++;
                        if (currentFileIndex < parts.length - 1) {
                            currentFileSize = HexDump.hexStringToAlgorism(parts[currentFileIndex + 1]);
                            LogUtils.e("下一个文件大小" + currentFileSize);
                            fileDataSize = 0;
                            currentFileData = new byte[currentFileSize];
                            sendDataToHost(HexDump.str2HexStr("OK"));

                        } else {
                            // 所有文件都已接收完毕
                            currentFileData = null;
                            currentFileSize = 0;
                            receivingFile = false;
                            LogUtils.e("所有文件都已接收完毕");
                            sendDataToHost("END");
                        }
                    } else {
                        // 数据块大小为1KB，开始验证
                        byte receivedLRC = mBytes[1024];
                        byte[] dataWithoutLRC = Arrays.copyOf(currentFileData, 1024);
                        byte expectedLRC = calculateLRC(dataWithoutLRC);
                        LogUtils.e("接受过来的LRC: " + receivedLRC);
                        LogUtils.e("进行验证LRC：" + expectedLRC);

                        // 验证LRC
                        if (receivedLRC == expectedLRC) {
                            // 数据块验证通过
                            // 文件保存逻辑
                            saveReceivedFileData(dataWithoutLRC, 1024, currentFileIndex);
                            sendDataToHost(HexDump.str2HexStr("OK"));
                        } else {
                            // 数据块验证失败，应答 ERR 并等待重发
                            sendDataToHost(HexDump.str2HexStr("ERR"));
                            // 重置文件数据
                            currentFileData = new byte[currentFileSize];
                            currentFileDataOffset = 0;
                        }
                    }
                }
            }
        } else {
            String content = new String(mBytes, 0, bytesRead);
            LogUtils.e(content);
            if (content.startsWith("5553425F5570646174653B")) {
                // 主机发送文件信息命令
                parts = content.split("3B");
                if (parts.length >= 2) {
                    currentFileIndex = 0; // 从第一个文件开始
                    currentFileSize = HexDump.hexStringToAlgorism(parts[currentFileIndex + 1]);
                    LogUtils.e("第一个文件大小" + currentFileSize);
                    currentFileData = new byte[currentFileSize];
                    currentFileDataOffset = 0;
                    receivingFile = true;
                    Message msg = new Message();
                    msg.what = RECEIVER_MESSAGE_SUCCESS;
                    msg.obj = 0;
                    mHandler.sendMessage(msg);
                    sendDataToHost(HexDump.str2HexStr("OK"));
                } else {
                    // 无效的命令，应答 ERR
                    sendDataToHost(HexDump.str2HexStr("ERR"));
                }
            }
        }

    }

    private void sendDataToHost(String message) {
        if (!TextUtils.isEmpty(message)) {
            mThreadPool.execute(() -> {
                try {
                    mFileOutputStream.write(message.getBytes());
                    mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS);
                } catch (IOException e) {
                    handleException(e);
                }
            });
        }
    }

    private byte calculateLRC(byte[] data) {
        byte lrc = 0;
        for (byte b : data) {
            lrc ^= b;
        }
        return lrc;
    }


    private void saveReceivedFileData(byte[] data, int dataSize, int fileIndex) {
        // 保存接收到的文件数据
        String directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
        String fileName = (fileIndex + 1) + ".bin"; // 可根据需要修改文件名和格式
        File file = new File(directoryPath, fileName);

        try {
            FileOutputStream fos = new FileOutputStream(file, true); // 追加模式
            fos.write(data, 0, dataSize);
            fos.close();
        } catch (IOException e) {
            handleException(e);
        }
    }

    private void handleException(Exception e) {
        // Handle exceptions, e.g., show an error message
        e.printStackTrace();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(UsbaccessoryaoaActivity.this,
                        "An error occurred: " + e.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.usbaccessorysend) {
            sendDataToHost(usbaccessorymessage.getText().toString());
        }
    }

    @Override
    public void openAccessoryModel(UsbAccessory usbAccessory) {

    }

    @Override
    public void openAccessoryError() {

    }

    @Override
    public void usbDetached() {
        finish();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mOpenAccessoryReceiver);
        closeAccessory();
    }

    private void closeAccessory() {
        if (mParcelFileDescriptor != null) {
            try {
                mParcelFileDescriptor.close();
            } catch (IOException e) {
                handleException(e);
            }
        }
    }
}